#include "stdafx.h"

int SheetView::iColSet = 0;
int SheetView::iRowSet = 0;

SheetView::SheetView()
{
	pSheet = 0;
	leftCornerCell.iRow =1;
	leftCornerCell.iCol =1;
	selectingCell.iRow = 1;
	selectingCell.iCol = 1;
	regionStartCell.iRow = 1;
	regionStartCell.iCol =1;
	regionEndCell.iRow = 1;
	regionEndCell.iCol = 1;
	arrColLines = 0;
	arrRowLines = 0;
	rowHeaderWidth = ROW_HEADER_WIDTH_DEF;
	colHeaderHeight = COL_HEADER_HEIGHT;
}

SheetView::~SheetView()
{
	delete [] arrColLines;
	delete [] arrRowLines;
}

void SheetView::SetClientSize(int x, int y)
{
	xClient = x;
	yClient = y;
}

void SheetView::SetLeftCorner(ROW_NUM iRow, COL_NUM iCol)
{
	leftCornerCell.iRow = iRow;
	leftCornerCell.iCol = iCol;
}

bool SheetView::SetSelectingCell(ROW_NUM iRow, COL_NUM iCol)
{
	if ( iRow <= 0 || iRow> ROW_MAX || iCol > COL_MAX || iCol<=0)
	{
		return false;
	}
	selectingCell.iRow = iRow;
	selectingCell.iCol = iCol;
	return true;
}

void SheetView::SetRegionStart(ROW_NUM iRow, COL_NUM iCol)
{
	if ( iRow <= 0 || iRow> ROW_MAX || iCol > COL_MAX || iCol<=0)
	{
		return;
	}
	regionStartCell.iRow = iRow;
	regionStartCell.iCol = iCol;
}

void SheetView::SetRegionEnd(ROW_NUM iRow, COL_NUM iCol, bool HScroll, bool VScroll)
{
	if ( iRow <= 0 || iRow> ROW_MAX || iCol > COL_MAX || iCol<=0)
	{
		return;
	}
	regionEndCell.iRow = iRow;
	regionEndCell.iCol = iCol;
	if (HScroll)
	{
		while(leftCornerCell.iCol + colLines.GetCount() -1 <= iCol)
		{
			leftCornerCell.iCol++;
		}
		while(leftCornerCell.iCol > iCol && leftCornerCell.iCol != 1)
		{
			leftCornerCell.iCol--;
		}
	}
	if (VScroll)
	{
		while(leftCornerCell.iRow + rowLines.GetCount() -2 <= iRow)
		{
			leftCornerCell.iRow++;
		}
		while(leftCornerCell.iRow > iRow && leftCornerCell.iRow != 1)
		{
			leftCornerCell.iRow--;
		}
	}
}

RECT SheetView::GetSelectingRect()
{
	return GetCellRect(selectingCell.iRow, selectingCell.iCol);
}

RECT SheetView::GetRegionRect()
{
	RECT rectRegion = {0,0,0,0};
	RECT rectStart = GetRegionCellRect(regionStartCell.iRow, regionStartCell.iCol);
	RECT rectEnd = GetRegionCellRect(regionEndCell.iRow, regionEndCell.iCol);
	rectRegion.top = rectStart.top < rectEnd.top ? rectStart.top : rectEnd.top;
	rectRegion.left = rectStart.left < rectEnd.left ? rectStart.left : rectEnd.left;
	rectRegion.right = rectStart.right > rectEnd.right ? rectStart.right : rectEnd.right;
	rectRegion.bottom = rectStart.bottom > rectEnd.bottom ? rectStart.bottom : rectEnd.bottom;
	return rectRegion;
}

RECT SheetView::GetRegionCellRect(ROW_NUM iRow, ROW_NUM iCol)
{
	RECT rect = {0,0,0,0};
	if (iRow > ROW_MAX || iCol > COL_MAX)
		return rect;

	int delRow = iRow - leftCornerCell.iRow;
	int delCol = iCol - leftCornerCell.iCol;
	
	int r_top = 0, r_bottom = 0, r_left = 0, r_right = 0;
	if (delRow >0 && delRow < rowLines.GetCount() + 1)
		r_top = arrRowLines[delRow-1];
	if (delRow >= 0 && delRow < rowLines.GetCount())
		r_bottom = arrRowLines[delRow];
	if (delCol >0 && delCol < colLines.GetCount()+1)
		r_left = arrColLines[delCol -1];
	if (delCol >= 0 && delCol < colLines.GetCount())
		r_right = arrColLines[delCol];

	if (iRow >= leftCornerCell.iRow + rowLines.GetCount())
	{
		r_bottom = yClient+50;
		r_top = yClient + 50;
	}
	else if(iRow < leftCornerCell.iRow)
	{
		r_top = -50;
		r_bottom = - 50;
	}
	if (iCol >= leftCornerCell.iCol + colLines.GetCount())
	{
		r_left = xClient + 50;
		r_right = xClient+50;
	}
	else if(iCol < leftCornerCell.iCol )
	{
		r_left = -50;
		r_right = -50;
	}

	if (ApplicationSetting::ShowHeader)
	{
		r_top += GetColHeaderHeight();
		r_bottom += GetColHeaderHeight();
		r_left += GetRowHeaderWidth();
		r_right += GetRowHeaderWidth();
	}

	rect.top = r_top; rect.bottom = r_bottom;
	rect.left = r_left; rect.right = r_right;
	return rect;
}


RECT SheetView::GetCellRect(ROW_NUM iRow, ROW_NUM iCol)
{
	RECT rect = {0,0,0,0};
	if (iRow > ROW_MAX || iCol > COL_MAX)
		return rect;

	if (iRow >= leftCornerCell.iRow + rowLines.GetCount() || iRow < leftCornerCell.iRow ) 
	{
		return rect;
	}
	if (iCol >= leftCornerCell.iCol + colLines.GetCount() || iCol < leftCornerCell.iCol ) 
	{
		return rect;
	}
	
	int delRow = iRow - leftCornerCell.iRow;
	int delCol = iCol - leftCornerCell.iCol;

	int r_top = 0, r_bottom = 0, r_left = 0, r_right = 0;
	if (delRow >0 && delRow < rowLines.GetCount() + 1)
		r_top = arrRowLines[delRow-1];
	if (delRow >= 0 && delRow < rowLines.GetCount())
		r_bottom = arrRowLines[delRow];
	if (delCol >0 && delCol < colLines.GetCount()+1)
		r_left = arrColLines[delCol -1];
	if (delCol >= 0 && delCol < colLines.GetCount())
		r_right = arrColLines[delCol];

	if (ApplicationSetting::ShowHeader)
	{
		r_top += GetColHeaderHeight();
		r_bottom += GetColHeaderHeight();
		r_left += GetRowHeaderWidth();
		r_right += GetRowHeaderWidth();
	}
	
	rect.top = r_top; rect.bottom = r_bottom;
	rect.left = r_left; rect.right = r_right;
	return rect;
}
//void SheetView::ScrollDown(ROW_NUM i)
//{
//	leftCornerCell.iRow = (leftCornerCell.iRow + i > ROW_MAX) ? ROW_MAX : leftCornerCell.iRow + i;
//}
//
//void SheetView::ScrollRight(COL_NUM i)
//{
//	leftCornerCell.iCol = (leftCornerCell.iCol + i > COL_MAX) ? COL_MAX : leftCornerCell.iCol + i;
//}
//
//void SheetView::ScrollLeft(COL_NUM i)
//{
//	leftCornerCell.iCol = (leftCornerCell.iCol - i < 0) ? 0 : leftCornerCell.iCol - i;
//}
//
//void SheetView::ScrollUp(ROW_NUM i)
//{
//	leftCornerCell.iRow = (leftCornerCell.iRow - i < 0) ? 0 : leftCornerCell.iRow - i;
//}

const int SheetView::GetRowHeaderWidth()
{
	float zoom = ApplicationSetting::Zooming;
	if (leftCornerCell.iRow + rowLines.GetCount() >= 10000)
		rowHeaderWidth = (int)(45 * zoom);
	else if(leftCornerCell.iRow + rowLines.GetCount() >= 1000)
		rowHeaderWidth = (int)(40 * zoom);
	else
		rowHeaderWidth = (int)(35 * zoom);
	return rowHeaderWidth;
}

void SheetView::ReadRowHeight()
{
	float zoom = ApplicationSetting::Zooming;
	bool isFinished = false;
	rowLines.Clear();
	delete [] arrRowLines;

	Document* currentDoc = Application::GetDocument();
	Sheet* currentSheet = currentDoc->GetSheet();

	int iCurrentRow = leftCornerCell.iRow -1;
	int iSumHeight = 0;
	RowHeader* pRowHeader = currentSheet->GetRowHead();
	RowHeader* pCurrent = pRowHeader;
	while (pCurrent->pCellBelow != 0)
	{
		pCurrent = (RowHeader*)(pCurrent->pCellBelow);
		if (pCurrent->iRowNum < leftCornerCell.iRow)
		{
			continue;
		}
		if (pCurrent->iRowNum != iCurrentRow + 1)
		{
			// Use Default Value for empty column
			for (int j = 1; j < pCurrent->iRowNum - iCurrentRow; j++)
			{
				// Add to check if the column is enough
				iSumHeight += (int)(CELL_DEFHEIGHT * zoom);
				rowLines.Append((int)iSumHeight);

				if (iSumHeight >= yClient)
				{
					isFinished = true;
					break;
				}
			}
		}
		if (isFinished)
			break;
		iSumHeight += (int)(pCurrent->iRowHeight * zoom);
		rowLines.Append(iSumHeight);

		if (iSumHeight >= yClient)
		{
			isFinished = true;
			break;
		}
		iCurrentRow = pCurrent->iRowNum;
	}
	// if the sheet has very little column, use default value
	while (iSumHeight < yClient)
	{
		iSumHeight += (int)(CELL_DEFHEIGHT * zoom);
		rowLines.Append(iSumHeight);
	}
	arrRowLines = new int[rowLines.GetCount()];
	for (int i=0; i<rowLines.GetCount(); i++)
	{
		rowLines.GetElement(i+1, arrRowLines[i]);
	}
	return;
}

void SheetView::ReadColumnWidth()
{
	float zoom = ApplicationSetting::Zooming;
	bool isFinished = false;
	colLines.Clear();
	delete [] arrColLines;

	// A array stores the width of current Column
	//int* colWidth = new int[(xClient/CELL_DEFWIDTH)*2];
	Document* currentDoc = Application::GetDocument();
	Sheet* currentSheet = currentDoc->GetSheet();

	int iCurrentCol = leftCornerCell.iCol - 1;
	int iSumWidth = 0;
	ColHeader* pColHeader = currentSheet->GetColHead();
	ColHeader* pCurrent = pColHeader;
	while (pCurrent->pCellRight != 0)
	{
		pCurrent = (ColHeader*)(pCurrent->pCellRight);
		if (pCurrent->iColNum < leftCornerCell.iCol)
		{
			//iCurrentCol = pCurrent->iColNum;
			continue;
		}
		if (pCurrent->iColNum != iCurrentCol + 1)
		{
			// Use Default Value for empty column
			for (int j = 1; j < pCurrent->iColNum - iCurrentCol; j++)
			{
				// Add to check if the column is enough
				iSumWidth += (int)(CELL_DEFWIDTH * zoom);
				colLines.Append(iSumWidth);

				if (iSumWidth >= xClient)
				{
					isFinished = true;
					break;// colWidth;
				}
			}
		}
		if (isFinished)
			break;
		iSumWidth += (int)(pCurrent->iColWidth*zoom);
		colLines.Append(iSumWidth);

		if (iSumWidth >= xClient)
		{
			isFinished = true;
			break;// colWidth;
		}

		iCurrentCol = pCurrent->iColNum;
	}
	// if the sheet has very little column, use default value
	while (iSumWidth < xClient)
	{
		iSumWidth += (int)(CELL_DEFWIDTH * zoom);
		colLines.Append(iSumWidth);
	}
	arrColLines = new int[colLines.GetCount()];
	for (int i=0; i<colLines.GetCount(); i++)
	{
		colLines.GetElement(i+1, arrColLines[i]);
	}
	return;// colWidth;
}

SheetView::AREA SheetView::CheckArea(int x, int y, ROW_NUM& iRow, COL_NUM& iCol)
{
	if (ApplicationSetting::ShowHeader)
	{
		if (x < rowHeaderWidth && y < colHeaderHeight)
		{
			iRow = max(0, leftCornerCell.iRow-1);
			iCol = max(0, leftCornerCell.iCol-1);
			return CORNER_BUTTON;
		}
		else if (y < GetColHeaderHeight())
		{
			// Check for on line
			for (int i = 0; i < colLines.GetCount(); i++)
			{
				int thisLine = 0;
				thisLine = arrColLines[i];
				//colLines.GetElement(i+1,thisLine);
				thisLine += GetRowHeaderWidth();
				if (x > thisLine-3 && x < thisLine+3)
				{
					iRow = max(0, leftCornerCell.iRow-1);
					iCol = leftCornerCell.iCol + i;
					return COL_LINE;
				}
				if (x < thisLine)
				{
					iRow = max(0, leftCornerCell.iRow-1);
					iCol = leftCornerCell.iCol + i;
					return COL_HEADER;
				}
			}
			return COL_HEADER;
		}
		else if( x < GetRowHeaderWidth())
		{
			// Check for on line
			for (int i = 0; i < rowLines.GetCount(); i++)
			{
				int thisLine = 0;
				thisLine = arrRowLines[i];
				//rowLines.GetElement(i+1,thisLine);
				thisLine += GetColHeaderHeight();
				if (y > thisLine-3 && y < thisLine+3)
				{
					iRow = leftCornerCell.iRow + i;
					iCol = max(0, leftCornerCell.iCol-1);
					return ROW_LINE;
				}
				
				if (y < thisLine)
				{
					iRow = leftCornerCell.iRow + i;
					iCol = max(0, leftCornerCell.iCol-1);
					return ROW_HEADER;
				}
			}
			return ROW_HEADER;
		}
		else if(x > xClient && y> yClient)
		{
			iCol = min(leftCornerCell.iCol + colLines.GetCount() + 1, COL_MAX);
			iRow = min(leftCornerCell.iRow + rowLines.GetCount() + 1, ROW_MAX);
		}
		else if(x > xClient)
		{
			iCol = min(leftCornerCell.iCol + colLines.GetCount() + 1, COL_MAX);
		}
		else if(y> yClient)
		{
			iRow = min(leftCornerCell.iRow + rowLines.GetCount() + 1, ROW_MAX);
		}
	}
	CheckCell(x, y, iRow, iCol);
	return GRID_AREA;
}

void SheetView::CheckCell(int x, int y, ROW_NUM& iRow, COL_NUM& iCol)
{
	for (int i = 0; i< rowLines.GetCount(); i++)
	{
		int currentHeight =  0;
		currentHeight = arrRowLines[i];
		//rowLines.GetElement(i+1, currentHeight);
		if (ApplicationSetting::ShowHeader)
			currentHeight += GetColHeaderHeight();
		if (y < currentHeight)
		{
			iRow = leftCornerCell.iRow + i;
			break;
		}
	}

	for (int i =0; i< colLines.GetCount(); i++)
	{
		int currentWidth = 0;
		currentWidth = arrColLines[i];
		//colLines.GetElement(i+1, currentWidth);
		if (ApplicationSetting::ShowHeader)
			currentWidth += GetRowHeaderWidth();
		if (x < currentWidth)
		{
			iCol = leftCornerCell.iCol + i;
			break;
		}
	}
}


void SheetView::nToA(int n, PTSTR outszStr)
{
	TCHAR buf[6] = TEXT("");
	TCHAR bufCurrent[6] = TEXT("");
	enum {BASE = 26};

	while ((float)n/(float)BASE != 0.0)
	{
		n--;
		bufCurrent[0] = 'A' + n%BASE;
		::_tcscat_s(bufCurrent, 6, buf);
		::wsprintf(buf, TEXT("%s"), bufCurrent);
		n = n/BASE;
	}
	wsprintf(outszStr, TEXT("%s"), bufCurrent);

	return;
}

void SheetView::SetColWidth(int Width)
{
	int iCol = iColSet;
	if (ApplicationSetting::ShowHeader)
		Width -= GetRowHeaderWidth();
	int i = iCol - leftCornerCell.iCol;
	int dWidth = Width - arrColLines[i];
	int newWidth = arrColLines[i] + dWidth;
	
	if (newWidth < arrColLines[i-1] + 1 || newWidth < 0)
		return;//SetColWidth(iCol -1 , arrColLines[i-1] - 1);

	for (int j = i; j < colLines.GetCount(); j++)
	{
		arrColLines[j] += dWidth;
	}
}

void SheetView::SetRowHeight(int Height)
{
	int iRow = iRowSet;
	if (ApplicationSetting::ShowHeader)
		Height -= GetColHeaderHeight();
	int i = iRow - leftCornerCell.iRow;
	int dHeight = Height - arrRowLines[i];
	int newHeight = arrRowLines[i] + dHeight;

	if (newHeight < arrRowLines[i-1] || newHeight < 0)
		return;
	for (int j = i; j < rowLines.GetCount(); j++)
	{
		arrRowLines[j] += dHeight;
	}
}

// out: the column modified and the new width
void SheetView::EndSetColWidth(COL_NUM& iCol, int& NewWidth)
{
	iCol = iColSet;
	int i = iCol - leftCornerCell.iCol;
	if ( i-1 >= 0)
		NewWidth = arrColLines[i] - arrColLines[i-1];
	else
		NewWidth = arrColLines[i];
	iColSet = 0;
}

void SheetView::EndSetRowHeight(ROW_NUM& iRow, int& NewHeight)
{
	iRow = iRowSet;
	int i = iRowSet - leftCornerCell.iRow;
	if( i-1 >= 0)
		NewHeight = arrRowLines[i] - arrRowLines[i-1];
	else
		NewHeight = arrRowLines[i];
	iRowSet = 0;
}

bool SheetView::InRegion(const CELLPOS& Pos)
{
	return Pos.iRow <= max(regionStartCell.iRow, regionEndCell.iRow)
		&& Pos.iRow >= min(regionStartCell.iRow, regionEndCell.iRow)
		&& Pos.iCol >= min(regionStartCell.iCol, regionEndCell.iCol)
		&& Pos.iCol <= max(regionStartCell.iCol, regionEndCell.iCol);
}